﻿using System;
using System.Diagnostics;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Shapes;

namespace Game.Surface
{
    public class GameCanvas : Panel
    {
        public static readonly DependencyProperty GameTopProperty = DependencyProperty.RegisterAttached(
            "GameTop", typeof(double), typeof(GameCanvas), 
            new FrameworkPropertyMetadata(
                0d, 
                FrameworkPropertyMetadataOptions.AffectsArrange,
                new PropertyChangedCallback(OnTopChanged)
               )
           );
        
        public static readonly DependencyProperty GameLeftProperty = DependencyProperty.RegisterAttached(
            "GameLeft", typeof(double), typeof(GameCanvas), 
            new FrameworkPropertyMetadata(
                0d, 
                FrameworkPropertyMetadataOptions.AffectsArrange,
                new PropertyChangedCallback(OnLeftChanged)
               )
           );
        
        public static readonly DependencyProperty GameIsDirtyProperty = DependencyProperty.RegisterAttached(
            "GameIsDirty", typeof(bool), typeof(GameCanvas), 
            new FrameworkPropertyMetadata(true)
           );
        
        static void OnLeftChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var p = d as FrameworkElement;
            var pp = p.Parent as FrameworkElement;
            if (pp != null)
            {
                pp.InvalidateArrange();
            }
        }

        static void OnTopChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var p = d as FrameworkElement;
            var pp = p.Parent as FrameworkElement;
            if (pp != null)
            {
                pp.InvalidateArrange();
            }
        }

        public static double GetGameTop(UIElement element)
        {
            return (double)element.GetValue(GameTopProperty);
        }

        public static double GetGameLeft(UIElement element)
        {
            return (double)element.GetValue(GameLeftProperty);
        }

        public static bool GetGameIsDirty(UIElement element)
        {
            return (bool)element.GetValue(GameIsDirtyProperty);
        }
        
        public static void SetGameLeft(UIElement element, double value)
        {
            element.SetValue(GameLeftProperty, value);
            SetGameIsDirty(element, true);
        }

        public static void SetGameTop(UIElement element, double value)
        {
            element.SetValue(GameTopProperty, value);
            SetGameIsDirty(element, true);
        }

        public static void SetGameIsDirty(UIElement element, bool value)
        {
            element.SetValue(GameIsDirtyProperty, value);
        }
        
        public GameCanvas()
        {
            base.Width = 6000;
            base.Height = 6000;
        }

        public double OriginX { get; set; }

        public double OriginY { get; set; }

        public AbstractField HitTest(MouseButtonEventArgs e)
        {
            foreach(var c in Children)
            {
                var field = c as AbstractField;
                if (field != null)
                {
                    Point local = e.GetPosition(field);
                    bool hit = field.Clip.FillContains(local, 0, ToleranceType.Relative);
                    if (hit)
                    {
                        return field;
                    }
                }
            }
            
            return null;
        }

        protected override Size MeasureOverride(Size availableSize)
        {
            foreach (var child in base.Children)
            {
                var field = child as AbstractField;
                if (field != null)
                {
                    field.Measure(new Size(AbstractField.Size, AbstractField.Size));
                }
                else
                {
                    var e = child as UIElement;
                    if (e != null)
                    {
                        e.Measure(new Size(AbstractField.Size, AbstractField.Size));
                    }
                }
            }

            return availableSize;
        }
        
        protected override Size ArrangeOverride(Size finalSize)
        {
            foreach (var child in base.Children)
            {
                bool dirty = GameCanvas.GetGameIsDirty(child as UIElement);
                if (!dirty)
                {
                    continue;
                }
                
                var field = child as AbstractField;
                if (field != null)
                {
                    var x = GameCanvas.GetGameLeft(field);
                    var y = GameCanvas.GetGameTop(field);
                     
                    x += 100;
                    field.Arrange(new Rect(new Point(x, y), new Size(200, 200)));
                }
                else
                {
                    var e = child as UIElement;
                    if (e != null)
                    {
                        var x = GameCanvas.GetGameLeft(e);
                        var y = GameCanvas.GetGameTop(e);
                        y -= 100;
                        e.Arrange(new Rect(new Point(x, y), new Size(200, 200)));
                    }
                }
                
            }

            return new Size(6000, 6000);
        }

    }
}
